package com.itheima.p3_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//定义工具类,产生接口实现类的代理对象
public class ProxyUtil {
    //构造方法私有
    private ProxyUtil() {
    }
    //定义静态方法,获取接口实现类的代理对象
    public static Object createProxy(Object obj) {
        //创建UserServiceImpl类的对象
        UserServiceImpl userService = new UserServiceImpl();
        //1.获取被代理对象的Class对象
        Class<? extends UserServiceImpl> clazz = userService.getClass();
        //2.获取被代理对象的类加载器对象
        ClassLoader classLoader = clazz.getClassLoader();
        //3.获取被代理对象所实现的所有的接口对应的Class对象数组
        Class<?>[] interfaces = clazz.getInterfaces();
        //4.多态的方式创建InvocationHandler接口的匿名内部类对象,指定对被代理对象如何代理
        InvocationHandler invocationHandler = new InvocationHandler() {
            /*
               invoke方法: 使用代理对象调用的任何方法都要经过invoke方法,具有拦截的作用
               Object proxy: 产生的代理对象,目前我们不需要使用
               Method method: 使用代理对象调用的方法被装成成了Method对象,本质是接口中方法的Method对象
               Object[] args: 代理对象调用方法时,传递的参数
               返回值Object: 调用被代理对象的方法的返回的具体的结果数据
            */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long start = System.nanoTime();
                Object obj = method.invoke(userService, args);
                long end = System.nanoTime();
                System.out.println(method.getName() + "方法, 执行总耗时: " + (end - start) + "纳秒");
                return obj;
            }
        };
        Object proxyobj = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxyobj;
    }

    //定义静态方法,获取接口实现类的代理对象
    public static  <T> T createProxy2(T obj) {
        //创建UserServiceImpl类的对象
        UserServiceImpl userService = new UserServiceImpl();
        //1.获取被代理对象的Class对象
        Class<? extends UserServiceImpl> clazz = userService.getClass();
        //2.获取被代理对象的类加载器对象
        ClassLoader classLoader = clazz.getClassLoader();
        //3.获取被代理对象所实现的所有的接口对应的Class对象数组
        Class<?>[] interfaces = clazz.getInterfaces();
        //4.多态的方式创建InvocationHandler接口的匿名内部类对象,指定对被代理对象如何代理
        InvocationHandler invocationHandler = new InvocationHandler() {
            /*
               invoke方法: 使用代理对象调用的任何方法都要经过invoke方法,具有拦截的作用
               Object proxy: 产生的代理对象,目前我们不需要使用
               Method method: 使用代理对象调用的方法被装成成了Method对象,本质是接口中方法的Method对象
               Object[] args: 代理对象调用方法时,传递的参数
               返回值Object: 调用被代理对象的方法的返回的具体的结果数据
            */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long start = System.nanoTime();
                Object result = method.invoke(obj, args);
                long end = System.nanoTime();
                System.out.println(method.getName() + "方法, 执行总耗时: " + (end - start) + "纳秒");
                return result;
            }
        };

        return (T)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }

}
